#ifndef __MY_SINK__
#define __MY_SINK__
#include "utils.hpp"
#include "message.hpp"
#include "formater.hpp"
#include <memory>
#include <mutex>
#include <iomanip>

namespace wzh
{
    class LogSink
    {
    public:
        using ptr = std::shared_ptr<LogSink>;
        LogSink() {}
        virtual ~LogSink() {}
        virtual void log(const char *data, size_t len) = 0;
    };

    class StdoutSink : public LogSink
    {
    public:
        using ptr = std::shared_ptr<StdoutSink>;
        StdoutSink() = default;
        void log(const char *data, size_t len)
        {
            std::cout.write(data, len);
        }
    };

    class FileSink : public LogSink
    {
    public:
        using ptr = std::shared_ptr<FileSink>;
        FileSink(const std::string &filename) : _filename(filename)
        {
            util::File::create_directory(util::File::path(filename));
            _ofs.open(_filename, std::ios::binary | std::ios::app);
            assert(_ofs.is_open());
        }

        const std::string &file() { return _filename; }

        void log(const char *data, size_t len)
        {
            _ofs.write((const char *)data, len);
            if (!_ofs.good())
            {
                std::cout << "日志输出文件失败！\n";
            }
        }

    private:
        std::string _filename;
        std::ofstream _ofs;
    };

    class RollSink : public LogSink
    {
    public:
        using ptr = std::shared_ptr<RollSink>;
        RollSink(const std::string &basename, size_t max_fsize) : _basename(basename), _max_fsize(max_fsize), _cur_fsize(0)
        {
            util::File::create_directory(util::File::path(basename));
        }

        void log(const char *data, size_t len)
        {
            initLogFile();
            _ofs.write(data, len);
            if (_ofs.good() == false)
            {
                std::cout << "日志输出文件失败！\n";
            }
            _cur_fsize += len;
        }

    private:
        void initLogFile()
        {
            if (_ofs.is_open() == false || _cur_fsize >= _max_fsize)
            {
                _ofs.close();
                std::string name = createFilename();
                std::cout << name << std::endl;
                _ofs.open(name, std::ios::binary | std::ios::app);
                assert(_ofs.is_open());
                _cur_fsize = 0;
                return;
            }
            return;
        }

        std::string createFilename()
        {
            auto now = std::chrono::system_clock::now();
            std::time_t t = std::chrono::system_clock::to_time_t(now);
            struct tm lt;
            localtime_r(&t, &lt);

            // 获取当前时间的毫秒部分
            auto millisec = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()) % 1000;

            std::stringstream ss;
            ss << _basename;
            ss << lt.tm_year + 1900;
            ss << std::setw(2) << std::setfill('0') << lt.tm_mon + 1;
            ss << std::setw(2) << std::setfill('0') << lt.tm_mday;
            ss << std::setw(2) << std::setfill('0') << lt.tm_hour;
            ss << std::setw(2) << std::setfill('0') << lt.tm_min;
            ss << std::setw(2) << std::setfill('0') << lt.tm_sec;
            ss << "." << std::setw(3) << std::setfill('0') << millisec.count(); // 毫秒部分
            ss << ".log";
            return ss.str();
        }

    private:
        std::string _basename;
        std::ofstream _ofs;
        size_t _max_fsize;
        size_t _cur_fsize;
    };

    class SinkFactory
    {
    public:
        template <typename SinkType, typename... Args>
        static LogSink::ptr create(Args &&...args)
        {
            return std::make_shared<SinkType>(std::forward<Args>(args)...);
        }
    };

}
#endif